﻿using System;
using System.ServiceModel;
using Microsoft.ManagementConsole;
using SharpShare.Management.Mmc.Nodes;
using SharpShare.Configuration;
using SharpShare.Activation;
using System.Configuration;
using System.Drawing;
using System.Reflection;

namespace SharpShare.Management.Mmc {

    [SnapInSettings("{356774A2-17F0-4AE9-B885-CDA026F0C752}",
        DisplayName = "SharpShare",
        Description = "Manages the SharpShare service.",
        Vendor = "Andrew Christiansen")]
    public class SharpShareSnapIn : Microsoft.ManagementConsole.SnapIn {
        private bool _configurationChanged;

        public SharpShareSnapIn() {
            RegisterImages();

            this.SaveAction = new SyncAction(
                "Save and Apply", "Saves the new configuration and restarts the service.", (int)Icon.Disk, "SaveApply");
            this.SaveAction.Triggered += new SyncAction.SyncActionEventHandler(SaveActionTriggered);

            this.StartServiceAction = new SyncAction(
                "Start Service", "Starts the SharpShare service.", (int)Icon.Start, "StartService");
            this.StartServiceAction.Triggered += new SyncAction.SyncActionEventHandler(StartServiceActionTriggered);

            this.StopServiceAction = new SyncAction(
                "Stop Service", "Stops the SharpShare service.", (int)Icon.Stop, "StopService");
            this.StopServiceAction.Triggered += new SyncAction.SyncActionEventHandler(StopServiceActionTriggered);

            this.RootNode = new SharpShareNode();
        }

        private void RegisterImages() {
            BindingFlags bindingFlags = (System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.GetProperty);
            Array imageValues = System.Enum.GetValues(typeof(Icon));
            Type resType = typeof(Properties.Resources);

            foreach (Icon image in imageValues) {
                string smallPropName = image.ToString() + "Small";
                string largePropName = image.ToString() + "Large";
                Bitmap smallImage = (Bitmap)resType.InvokeMember(smallPropName, bindingFlags, null, null, null);
                Bitmap largeImage = (Bitmap)resType.InvokeMember(largePropName, bindingFlags, null, null, null);
                this.SmallImages.Add(smallImage);
                this.LargeImages.Add(largeImage);
            }
        }

        public new SharpShareNode RootNode {
            get {
                return (SharpShareNode)((SnapIn)this).RootNode;
            }
            set {
                ((SnapIn)this).RootNode = value;
            }
        }
        public IShareManager ShareManager { get; private set; }
        public System.Configuration.Configuration Configuration { get; set; }
        public SharpShareSectionGroup SharpShareConfiguration { get; private set; }
        public IExtensionFactory<StorageProviderElement> StorageProviderFactory { get; private set; }
        public IExtensionFactory<ServiceElement> ServiceFactory { get; private set; }

        private SyncAction SaveAction { get; set; }
        private SyncAction StartServiceAction { get; set; }
        private SyncAction StopServiceAction { get; set; }

        public void AddGlobalActions(ActionsPaneItemCollection collection) {
            collection.Add(new ActionSeparator());
            collection.Add(this.SaveAction);
            collection.Add(new ActionSeparator());
            collection.Add(this.StartServiceAction);
            collection.Add(this.StopServiceAction);
        }

        private void UpdateGlobalActions() {
            try {
                ShareManagerState state = this.ShareManager.State;

                switch (state) {
                    case ShareManagerState.Starting:
                    case ShareManagerState.Stopping:
                        this.StartServiceAction.Enabled = false;
                        this.StopServiceAction.Enabled = false;
                        this.SaveAction.Enabled = false;
                        break;
                    case ShareManagerState.Started:
                        this.StartServiceAction.Enabled = false;
                        this.StopServiceAction.Enabled = true;
                        this.SaveAction.Enabled = true;
                        break;
                    case ShareManagerState.Stopped:
                        this.StartServiceAction.Enabled = true;
                        this.StopServiceAction.Enabled = false;
                        this.SaveAction.Enabled = true;
                        break;
                }
            } catch {
                this.StartServiceAction.Enabled = false;
                this.StopServiceAction.Enabled = false;
                this.SaveAction.Enabled = false;
            }
        }

        public bool ConfigurationChanged {
            get {
                return _configurationChanged;
            }
            set {
                _configurationChanged = value;
                //  this.SaveAction.Enabled = value;
            }
        }
        public void RefreshConfiguration() {
            try {
                if (this.ShareManager == null || ((ICommunicationObject)this.ShareManager).State != CommunicationState.Opened) {
                    this.ShareManager = SharpShare.Management.ShareManager.CreateRemoteManager();
                    ((ICommunicationObject)this.ShareManager).Open();
                }

                string location = this.ShareManager.GetLocalConfigurationLocation();
                ExeConfigurationFileMap map = new ExeConfigurationFileMap() {
                    ExeConfigFilename = location
                };

                this.Configuration = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
                this.SharpShareConfiguration = SharpShareSectionGroup.GetSectionGroup(this.Configuration);

                this.StorageProviderFactory = new ConfigurationExtensionFactory<StorageProviderElement>(this.Configuration);
                this.ServiceFactory = new ConfigurationExtensionFactory<ServiceElement>(this.Configuration);

                this.RootNode.ConnectionException = null;
            } catch (Exception ex) {
                this.RootNode.ConnectionException = ex;
                this.ShareManager = null;
            }

            this.UpdateGlobalActions();
        }

        protected override void OnShutdown(AsyncStatus status) {
            base.OnShutdown(status);


        }

        protected override void OnInitialize() {
            base.OnInitialize();

            this.AddGlobalActions(this.RootNode.ActionsPaneItems);

            this.RefreshConfiguration();
        }

        #region SyncAction Handlers

        private void StopServiceActionTriggered(object sender, SyncActionEventArgs e) {
            e.Status.CanCancel = false;

            try {
                e.Status.ReportProgress(0, 0, "Stopping service...");
                this.ShareManager.Stop();
            } catch (Exception ex) {
                this.Console.ShowDialog(new Microsoft.ManagementConsole.Advanced.MessageBoxParameters() {
                    Buttons = System.Windows.Forms.MessageBoxButtons.OK,
                    Icon = System.Windows.Forms.MessageBoxIcon.Exclamation,
                    Caption = "Unable to stop service.",
                    Text = string.Format("The service could not be stopped.\r\n\r\n{0}", ex.Message)
                });
            }

            this.UpdateGlobalActions();
        }
        private void StartServiceActionTriggered(object sender, SyncActionEventArgs e) {
            e.Status.CanCancel = false;

            try {
                e.Status.ReportProgress(0, 0, "Starting service...");
                this.ShareManager.Start();
            } catch (Exception ex) {
                this.Console.ShowDialog(new Microsoft.ManagementConsole.Advanced.MessageBoxParameters() {
                    Buttons = System.Windows.Forms.MessageBoxButtons.OK,
                    Icon = System.Windows.Forms.MessageBoxIcon.Exclamation,
                    Caption = "Unable to start service.",
                    Text = string.Format("The service could not be started.\r\n\r\n{0}", ex.Message)
                });
            }

            this.UpdateGlobalActions();
        }
        private void SaveActionTriggered(object sender, SyncActionEventArgs e) {
            e.Status.CanCancel = false;

            try {
                e.Status.ReportProgress(1, 3, "Saving configuration...");
                this.Configuration.Save();
            } catch (Exception ex) {
                e.Status.Complete("Unable to save configuration.", false);
                this.Console.ShowDialog(new Microsoft.ManagementConsole.Advanced.MessageBoxParameters() {
                    Buttons = System.Windows.Forms.MessageBoxButtons.OK,
                    Icon = System.Windows.Forms.MessageBoxIcon.Exclamation,
                    Caption = "Unable to save.",
                    Text = string.Format("The configuration file could not be saved:\r\n\r\n{0}", ex.Message)
                });

                return;
            }

            try {
                e.Status.ReportProgress(2, 3, "Updating service...");
                this.ShareManager.UpdateConfiguration();

                e.Status.ReportProgress(3, 3, "Finishing up...");
                System.Threading.Thread.Sleep(1500);
            } catch (Exception ex) {
                e.Status.Complete("Unable to update service.", false);
                this.Console.ShowDialog(new Microsoft.ManagementConsole.Advanced.MessageBoxParameters() {
                    Buttons = System.Windows.Forms.MessageBoxButtons.OK,
                    Icon = System.Windows.Forms.MessageBoxIcon.Exclamation,
                    Caption = "Unable to update service.",
                    Text = string.Format("The configuration file was saved, but the service could not be updated:\r\n\r\n{0}", ex.Message)
                });

                return;
            }

            this.ConfigurationChanged = false;

            e.Status.Complete("Configuration applied.", true);
        }


        #endregion
    }
}
